package com.ruoyi.business.service.wecom.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.business.domain.dto.admin.wecom.WecomTagAddDTO;
import com.ruoyi.business.domain.dto.admin.wecom.WecomTagGroupAddDTO;
import com.ruoyi.business.domain.dto.admin.wecom.WecomTagGroupDelDTO;
import com.ruoyi.business.domain.dto.admin.wecom.WecomTagGroupEditDTO;
import com.ruoyi.business.domain.vo.wecom.admin.TbWecomTagGroupVO;
import com.ruoyi.business.domain.vo.wecom.admin.TbWecomTagVO;
import com.ruoyi.business.domain.wecom.TbWecomTag;
import com.ruoyi.business.domain.wecom.TbWecomTagGroup;
import com.ruoyi.business.mapper.wecom.TbWecomTagGroupMapper;
import com.ruoyi.business.service.wecom.ITbWecomTagGroupService;
import com.ruoyi.business.service.wecom.ITbWecomTagService;
import com.ruoyi.common.exception.ServiceException;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpExternalContactService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.external.WxCpUserExternalTagGroupInfo;
import me.chanjar.weixin.cp.bean.external.WxCpUserExternalTagGroupList;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class TbWecomTagGroupServiceImpl extends ServiceImpl<TbWecomTagGroupMapper, TbWecomTagGroup> implements ITbWecomTagGroupService {

    @Resource
    private ITbWecomTagService tbWecomTagService;

    @Resource
    private WxCpService wxCpService;

    @Override
    public List<TbWecomTagGroupVO> queryTagList(String name) {
        LambdaQueryWrapper<TbWecomTagGroup> tbWecomTagGroupLambdaQueryWrapper = Wrappers.lambdaQuery(TbWecomTagGroup.class)
            .eq(StringUtils.isNotEmpty(name), TbWecomTagGroup::getGroupName, name)
            .orderByDesc(TbWecomTagGroup::getGroupOrder)
            .orderByDesc(TbWecomTagGroup::getGroupCreateTime);
        List<TbWecomTagGroup> tbWecomTagGroupList = this.list(tbWecomTagGroupLambdaQueryWrapper);
        // 按照 tagGroupId 分组转 Map
        Map<String, List<TbWecomTagGroup>> tagGroupMap = tbWecomTagGroupList.stream()
            .collect(Collectors.groupingBy(TbWecomTagGroup::getGroupId));
        List<String> groupIds = tbWecomTagGroupList.stream().map(TbWecomTagGroup::getGroupId).collect(Collectors.toList());
        LambdaQueryWrapper<TbWecomTag> tbWecomTagLambdaQueryWrapper = Wrappers.lambdaQuery(TbWecomTag.class)
            .in(CollectionUtils.isNotEmpty(groupIds), TbWecomTag::getTagGroupId, groupIds)
            .or(StringUtils.isNotEmpty(name), qw -> qw.like(TbWecomTag::getTagName, name))
            .orderByDesc(TbWecomTag::getTagOrder)
            .orderByDesc(TbWecomTag::getTagCreateTime);
        List<TbWecomTag> tbWecomTagList = tbWecomTagService.list(tbWecomTagLambdaQueryWrapper);
        // 按照 tagGroupId 分组转 Map
        Map<String, List<TbWecomTag>> tagGroupTagMap = tbWecomTagList.stream()
            .collect(Collectors.groupingBy(TbWecomTag::getTagGroupId));
        // 比对两个Map的key值，找出 tagGroupTagMap 中存在但 tagGroupMap 中不存在的 groupId
        List<String> missingGroupIds = tagGroupTagMap.keySet().stream()
            .filter(groupId -> !tagGroupMap.containsKey(groupId) && StringUtils.isNotEmpty(groupId))
            .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(missingGroupIds)) {
            List<TbWecomTagGroup> list = this.list(Wrappers.lambdaQuery(TbWecomTagGroup.class).in(TbWecomTagGroup::getGroupId, missingGroupIds));
            // 加入到 tbWecomTagGroupList 中
            tbWecomTagGroupList.addAll(list);
        }
        List<TbWecomTagGroupVO> tbWecomTagGroupVOS = BeanUtil.copyToList(tbWecomTagGroupList, TbWecomTagGroupVO.class);
        tbWecomTagGroupVOS.forEach(dto -> {
            List<TbWecomTag> tbWecomTags = tagGroupTagMap.get(dto.getGroupId());
            if (CollectionUtils.isNotEmpty(tbWecomTags)) {
                List<TbWecomTagVO> tbWecomTagVOS = BeanUtil.copyToList(tbWecomTags, TbWecomTagVO.class);
                dto.setTbWecomTagVO(tbWecomTagVOS);
            } else {
                dto.setTbWecomTagVO(new ArrayList<>());
            }
        });
        tbWecomTagGroupVOS.sort(Comparator
            .comparing(TbWecomTagGroupVO::getGroupOrder, Comparator.nullsFirst(Long::compareTo))
            .reversed());
        // 对每个标签组内的标签列表按 tagOrder 降序排序
        tbWecomTagGroupVOS.forEach(dto -> {
            if (CollectionUtils.isNotEmpty(dto.getTbWecomTagVO())) {
                dto.getTbWecomTagVO().sort(Comparator
                    .comparing(TbWecomTagVO::getTagOrder, Comparator.nullsFirst(Long::compareTo))
                    .reversed());
            }
        });
        return tbWecomTagGroupVOS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addTagGroup(WecomTagGroupAddDTO tagGroup) {
        // 根据名称查询是否重复
        TbWecomTagGroup tbWecomTagGroup = this.getOne(Wrappers.lambdaQuery(TbWecomTagGroup.class)
            .eq(TbWecomTagGroup::getGroupName, tagGroup.getGroupName()));
        if (!ObjectUtils.isEmpty(tbWecomTagGroup)) {
            TbWecomTagGroup tbWecomTagGroupFindByName = this.getOne(Wrappers.lambdaQuery(TbWecomTagGroup.class).eq(TbWecomTagGroup::getGroupName, tagGroup.getGroupName()));
            if (!ObjectUtils.isEmpty(tbWecomTagGroupFindByName)) {
                throw new ServiceException("标签组名称不可以重复");
            }
        }
        long distinctCount = tagGroup.getWecomTagAddListDTO().stream()
            .map(WecomTagAddDTO::getTagName)
            .distinct()
            .count();

        if (distinctCount < tagGroup.getWecomTagAddListDTO().size()) {
            throw new ServiceException("标签名称不可以重复");
        }
        // 调用 企微sdk
        WxCpUserExternalTagGroupInfo wxCpUserExternalTagGroupInfo = new WxCpUserExternalTagGroupInfo();
        List<WxCpUserExternalTagGroupInfo.Tag> tagList = new ArrayList<>();
        WxCpUserExternalTagGroupInfo.TagGroup tagGroupAdd = new WxCpUserExternalTagGroupInfo.TagGroup();
        tagGroupAdd.setGroupId(tagGroup.getGroupId());
        tagGroupAdd.setGroupName(tagGroup.getGroupName());
        tagGroupAdd.setOrder(ObjectUtils.isEmpty(tagGroup.getOrder()) ? 1L : tagGroup.getOrder());
        List<WecomTagAddDTO> wecomTagAddListDTO = tagGroup.getWecomTagAddListDTO();
        for (WecomTagAddDTO addDTO : wecomTagAddListDTO) {
            WxCpUserExternalTagGroupInfo.Tag tagAdd = new WxCpUserExternalTagGroupInfo.Tag();
            tagAdd.setName(addDTO.getTagName());
            // 根据 名称查询 是否存在
            tagAdd.setOrder(ObjectUtils.isEmpty(addDTO.getOrder()) ? 1L : addDTO.getOrder());
            tagList.add(tagAdd);
        }
        tagGroupAdd.setTag(tagList);
        wxCpUserExternalTagGroupInfo.setTagGroup(tagGroupAdd);
        WxCpUserExternalTagGroupInfo res;
        try {
            res = wxCpService.getExternalContactService().addCorpTag(wxCpUserExternalTagGroupInfo);
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }
        // 插入标签  或者 标签组
        WxCpUserExternalTagGroupInfo.TagGroup tagGroupRes = res.getTagGroup();
        String groupId = tagGroupRes.getGroupId();
        // 查询 groupId 是否存在
        long count = this.count(Wrappers.lambdaQuery(TbWecomTagGroup.class).eq(TbWecomTagGroup::getGroupId, groupId));
        if (count == 0) {
            // 新增 标签组
            TbWecomTagGroup group = new TbWecomTagGroup();
            group.setId(IdWorker.getId());
            group.setGroupId(groupId);
            group.setGroupName(tagGroupRes.getGroupName());
            group.setGroupCreateTime(tagGroupRes.getCreateTime());
            group.setGroupOrder(tagGroupRes.getOrder());
            group.setGroupDeleted(0);
            group.setCreateTime(new Date());
            this.save(group);
        }
        // 新增标签
        List<TbWecomTag> tbWecomTagList = new ArrayList<>();
        List<WxCpUserExternalTagGroupInfo.Tag> tag = tagGroupRes.getTag();
        tag.forEach(tagItem -> {
            TbWecomTag tagAdd = new TbWecomTag();
            tagAdd.setId(IdWorker.getId());
            tagAdd.setTagId(tagItem.getId());
            tagAdd.setTagGroupId(groupId);
            tagAdd.setTagName(tagItem.getName());
            tagAdd.setTagCreateTime(tagItem.getCreateTime());
            tagAdd.setTagOrder(tagItem.getOrder());
            tagAdd.setTagDeleted(0);
            tagAdd.setCreateTime(new Date());
            tbWecomTagList.add(tagAdd);
        });
        tbWecomTagService.saveBatch(tbWecomTagList);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean editTagGroup(WecomTagGroupEditDTO editDTO) {
        // 查询 标签组
        TbWecomTagGroup tbWecomTagGroup = this.getOne(Wrappers.lambdaQuery(TbWecomTagGroup.class).eq(TbWecomTagGroup::getGroupId, editDTO.getId()));
        // 查询标签
        TbWecomTag tbWecomTag = tbWecomTagService.getOne(Wrappers.lambdaQuery(TbWecomTag.class).eq(TbWecomTag::getTagId, editDTO.getId()));

        if (!ObjectUtils.isEmpty(tbWecomTagGroup)) {
            // 修改标签组
            // 根据名称查询是否重复
            TbWecomTagGroup tbWecomTagGroupFindByName = this.getOne(Wrappers.lambdaQuery(TbWecomTagGroup.class).eq(TbWecomTagGroup::getGroupName, editDTO.getName()));
            if (!ObjectUtils.isEmpty(tbWecomTagGroupFindByName)) {
                throw new ServiceException("标签组名称不可以重复");
            }
        }
        if (!ObjectUtils.isEmpty(tbWecomTag)) {
            // 修改标签
            TbWecomTag tbWecomTagFindByName = tbWecomTagService.getOne(Wrappers.lambdaQuery(TbWecomTag.class).eq(TbWecomTag::getTagName, editDTO.getName()));
            if (!ObjectUtils.isEmpty(tbWecomTagFindByName)) {
                throw new ServiceException("标签名称不可以重复");
            }
        }
        try {
            wxCpService.getExternalContactService().editCorpTag(editDTO.getId(), editDTO.getName(), editDTO.getOrder());
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }
        // 修改标签组
        if (!ObjectUtils.isEmpty(tbWecomTagGroup)) {
            tbWecomTagGroup.setUpdateTime(new Date());
            tbWecomTagGroup.setGroupName(editDTO.getName());
            tbWecomTagGroup.setGroupOrder(Long.valueOf(editDTO.getOrder()));
            this.updateById(tbWecomTagGroup);


        }
        // 修改标签
        if (!ObjectUtils.isEmpty(tbWecomTag)) {
            tbWecomTag.setUpdateTime(new Date());
            tbWecomTag.setTagName(editDTO.getName());
            tbWecomTag.setTagOrder(Long.valueOf(editDTO.getOrder()));
            tbWecomTagService.updateById(tbWecomTag);
        }

        return true;
    }

    @Override
    public Boolean delTagGroup(WecomTagGroupDelDTO delDTO) {
        List<String> groupIds = delDTO.getGroupIds();
        List<String> tagIds = delDTO.getTagIds();
        if (CollectionUtils.isEmpty(groupIds) && CollectionUtils.isEmpty(tagIds)) {
            throw new ServiceException("参数有误");
        }
        String[] tagIdArray = CollectionUtils.isNotEmpty(tagIds)
            ? tagIds.toArray(new String[0])
            : null;

        String[] groupIdArray = CollectionUtils.isNotEmpty(groupIds)
            ? groupIds.toArray(new String[0])
            : null;
        try {
            wxCpService.getExternalContactService().delCorpTag(tagIdArray, groupIdArray);
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }
        if (CollectionUtils.isNotEmpty(groupIds)) {
            // 删除标签组
            this.remove(Wrappers.lambdaQuery(TbWecomTagGroup.class).in(TbWecomTagGroup::getGroupId, groupIds));
            // 删除标签
            tbWecomTagService.remove(Wrappers.lambdaQuery(TbWecomTag.class).in(TbWecomTag::getTagGroupId, groupIds));
        }

        if (CollectionUtils.isNotEmpty(tagIds)) {
            // 根据 tagIds 查询
            List<TbWecomTag> tbWecomTag = tbWecomTagService.list(Wrappers.lambdaQuery(TbWecomTag.class).in(TbWecomTag::getTagId, tagIds));
            if (CollectionUtils.isNotEmpty(tbWecomTag)) {
                TbWecomTag findAny = tbWecomTag.get(0);
                long count = tbWecomTagService.count(Wrappers.lambdaQuery(TbWecomTag.class).eq(TbWecomTag::getTagGroupId, findAny.getTagGroupId()));
                if (count == (long) tagIds.size()) {
                    this.remove(Wrappers.lambdaQuery(TbWecomTagGroup.class).eq(TbWecomTagGroup::getGroupId, findAny.getTagGroupId()));
                }
            }
            // 删除标签
            tbWecomTagService.remove(Wrappers.lambdaQuery(TbWecomTag.class).in(TbWecomTag::getTagId, tagIds));
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean sysSyncWecomTagData() {
        WxCpExternalContactService externalContactService = wxCpService.getExternalContactService();
        WxCpUserExternalTagGroupList corpTagList = null;
        try {
            corpTagList = externalContactService.getCorpTagList(null, null);
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }
        List<WxCpUserExternalTagGroupList.TagGroup> tagGroupList = corpTagList.getTagGroupList();
        this.remove(Wrappers.lambdaQuery(TbWecomTagGroup.class).eq(TbWecomTagGroup::getGroupDeleted, 0));
        tbWecomTagService.remove(Wrappers.lambdaQuery(TbWecomTag.class).eq(TbWecomTag::getTagDeleted, 0));
        List<TbWecomTagGroup> tbWecomTagGroupList = new ArrayList<>();
        for (WxCpUserExternalTagGroupList.TagGroup tagGroup : tagGroupList) {
            TbWecomTagGroup tbWecomTagGroup = new TbWecomTagGroup();
            tbWecomTagGroup.setId(IdWorker.getId());
            tbWecomTagGroup.setGroupId(tagGroup.getGroupId());
            tbWecomTagGroup.setGroupName(tagGroup.getGroupName());
            tbWecomTagGroup.setGroupOrder(tagGroup.getOrder());
            tbWecomTagGroup.setGroupCreateTime(tagGroup.getCreateTime());
            tbWecomTagGroup.setGroupDeleted(0);
            tbWecomTagGroup.setCreateTime(new Date());
            tbWecomTagGroupList.add(tbWecomTagGroup);
            List<WxCpUserExternalTagGroupList.TagGroup.Tag> tag = tagGroup.getTag();
            List<TbWecomTag> tbWecomTagList = new ArrayList<>();
            for (WxCpUserExternalTagGroupList.TagGroup.Tag tagGroupTag : tag) {
                TbWecomTag tagBean = new TbWecomTag();
                tagBean.setId(IdWorker.getId());
                tagBean.setTagGroupId(tagGroup.getGroupId());
                tagBean.setTagId(tagGroupTag.getId());
                tagBean.setTagName(tagGroupTag.getName());
                tagBean.setTagCreateTime(tagGroupTag.getCreateTime());
                tagBean.setTagOrder(tagGroupTag.getOrder());
                tagBean.setTagDeleted(0);
                tbWecomTagList.add(tagBean);
            }
            tbWecomTagService.saveBatch(tbWecomTagList);
        }
        this.saveBatch(tbWecomTagGroupList);
        return true;
    }
}
